using System;
using System.Collections.Generic;
using System.Text;
using Weazel.Math;

namespace Weazel.Gezel.Simulator.Reference.IpBlocks
{
  [IpBlockAttribute("opbipifslave")]
  public class OpbIpifSlave : AbstractIpBlock
  {
    private const string IP2Bus_IntrEvent = "IP2Bus_IntrEvent";
    private const string Bus2IP_Data = "Bus2IP_Data";
    private const string Bus2IP_BE = "Bus2IP_BE";
    private const string Bus2IP_RdCE = "Bus2IP_RdCE";
    private const string Bus2IP_WrCE = "Bus2IP_WrCE";
    private const string IP2Bus_Data = "IP2Bus_Data";
    private const string IP2Bus_Ack = "IP2Bus_Ack";
    private const string IP2Bus_Retry = "IP2Bus_Retry";
    private const string IP2Bus_Error = "IP2Bus_Error";
    private const string IP2Bus_ToutSup = "IP2Bus_ToutSup";

    private int iP2BUS_IntrEvent_index  = -1;
    private int bus2IP_Data_index       = -1;
    private int bus2IP_BE_index         = -1;
    private int bus2IP_RdCE_index       = -1;
    private int bus2IP_WrCE_index       = -1;
    private int iP2Bus_Data_index       = -1;
    private int iP2Bus_Ack_index        = -1;
    private int iP2Bus_Retry_index      = -1;
    private int iP2Bus_Error_index      = -1;
    private int iP2Bus_ToutSup_index    = -1;

    private int registers;
    public int Registers
    {
      get { return registers; }
      set { registers = value; }
    }

    private int interrupts;
    public int Interrupts
    {
      get { return interrupts; }
      set { interrupts = value; }
    }

    private uint lowAddress;
    public uint LowAddress
    {
      get { return lowAddress; }
      set { lowAddress = value; }
    }

    private uint highAddress;
    public uint HighAddress
    {
      get { return highAddress; }
      set { highAddress = value; }
    }

    public OpbIpifSlave(string name)
      : base(name)
    {
    }

    public List<Integer> IoValues
    {
      get
      {
        return ioValues;
      }
    }

    public override void SetParameter(string name)
    {
      string field = name.Substring(0, name.IndexOf('='));
      string value = name.Substring(name.IndexOf('=') + 1);

      if (field == "interrupts")
        interrupts = int.Parse(value);
      else if (field == "registers")
        registers = int.Parse(value);
      else if (field == "low_address")
        lowAddress = Convert.ToUInt32(value, 16);
      else if (field == "high_address")
        highAddress = Convert.ToUInt32(value, 16);
    }

    public override bool CheckTerminal(int n, string tname, IoDirection dir)
    {
      if (tname == IP2Bus_IntrEvent && dir == IoDirection.Input)
        iP2BUS_IntrEvent_index = n;
      else if (tname == Bus2IP_Data && dir == IoDirection.Output)
        bus2IP_Data_index = n;
      else if (tname == Bus2IP_BE && dir == IoDirection.Output)
        bus2IP_BE_index = n;
      else if (tname == Bus2IP_RdCE && dir == IoDirection.Output)
        bus2IP_RdCE_index = n;
      else if (tname == Bus2IP_WrCE && dir == IoDirection.Output)
        bus2IP_WrCE_index = n;
      else if (tname == IP2Bus_Data && dir == IoDirection.Input)
        iP2Bus_Data_index = n;
      else if (tname == IP2Bus_Ack && dir == IoDirection.Input)
        iP2Bus_Ack_index = n;
      else if (tname == IP2Bus_Retry && dir == IoDirection.Input)
        iP2Bus_Retry_index = n;
      else if (tname == IP2Bus_Error && dir == IoDirection.Input)
        iP2Bus_Error_index = n;
      else if (tname == IP2Bus_ToutSup && dir == IoDirection.Input)
        iP2Bus_ToutSup_index = n;

      return true;

      /*
      switch (n)
      {
        case 0:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == IP2Bus_IntrEvent);
        case 1:
          return (dir == AbstractIpBlock.IoDirection.Output && tname == Bus2IP_Data);
        case 2:
          return (dir == AbstractIpBlock.IoDirection.Output && tname == Bus2IP_BE);
        case 3:
          return (dir == AbstractIpBlock.IoDirection.Output && tname == Bus2IP_RdCE);
        case 4:
          return (dir == AbstractIpBlock.IoDirection.Output && tname == Bus2IP_WrCE);
        case 5:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == IP2Bus_Data);
        case 6:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == IP2Bus_Ack);
        case 7:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == IP2Bus_Retry);
        case 8:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == IP2Bus_Error);
        case 9:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == IP2Bus_ToutSup);

        default:
          throw new NotSupportedException("CheckTerminal() unknown 'n' value");
      }
       * */
    }

    uint bus2IP_Data;
    public void WriteBus2IP_Data(uint value)
    {
      bus2IP_Data = value;
      ioValues[bus2IP_Data_index].Assign(value);
    }

    uint bus2IP_BE;
    public void WriteBus2IP_BE(uint value)
    {
      bus2IP_BE = value;
      ioValues[bus2IP_BE_index].Assign(value); 
    }

    uint bus2IP_RdCE;
    public void WriteBus2IP_RdCE(uint value)
    {
      bus2IP_RdCE = value;
      ioValues[bus2IP_RdCE_index].Assign(value);
    }

    uint bus2IP_WrCE;
    public void WriteBus2IP_WrCE(uint value)
    {
      bus2IP_WrCE = value;
      ioValues[bus2IP_WrCE_index].Assign(value);
    }

    public uint ReadIP2Bus_IntrEvent()
    {
      return ioValues[iP2BUS_IntrEvent_index].ToUInt();
    }

    public uint ReadIP2Bus_Data()
    {
      return ioValues[iP2Bus_Data_index].ToUInt();
    }

    public uint ReadIP2Bus_Ack()
    {
      return ioValues[iP2Bus_Ack_index].ToUInt();
    }

    public uint ReadIP2Bus_Retry()
    {
      return ioValues[iP2Bus_Retry_index].ToUInt();
    }

    public uint ReadIP2Bus_Error()
    {
      return ioValues[iP2Bus_Error_index].ToUInt();
    }

    public uint ReadIP2Bus_ToutSup()
    {
      return ioValues[iP2Bus_ToutSup_index].ToUInt();
    }

    

    bool isEvaluating = false;

    public override void Evaluate(long g, bool topLevelCall)
    {
      if (isEvaluating)
        return;

      if (topLevelCall)
      {
        foreach (InputSignal i in Inputs)
        {
          ioValues[(int)ioMap[i]] = i.Evaluate(this, g);
        }
      }

      if (generation != g)
      {
        Run();
        generation = g;

        //isEvaluating = true;

        //// the output of this input block does NOT depend on the inputs

        ////eval calls to the outputs is to update their generation count
        //foreach (AbstractSignal ass in Outputs)
        //{
        //  Integer j = ass.Evaluate(this, g);
        //}

        //isEvaluating = false;

      }    
    }
    
    public override void Run()
    {
      /*
      for (int i = 0; i < ioValues.Count; i++)
        if (ioValues[i].ToUInt() != 0)
          System.Windows.Forms.MessageBox.Show("Hey!");
       * */

      string o0 = IP2Bus_IntrEvent  + ": " + ioValues[0].ToString();
      string o1 = IP2Bus_Data       + ": " + ioValues[1].ToString();
      string o2 = IP2Bus_Ack        + ": " + ioValues[2].ToString();
      string o3 = IP2Bus_Retry      + ": " + ioValues[3].ToString();
      string o4 = IP2Bus_Error      + ": " + ioValues[4].ToString();
      string o5 = IP2Bus_ToutSup    + ": " + ioValues[5].ToString();

      string r = o0 + " " + o1 + " " + o2 + " " + o3 + " " + o4 + " " + o5;

   //   Console.WriteLine(r);

     //System.Windows.Forms.MessageBox.Show(r);
    }
  }
}
